#include "escalonadorFifo.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int IDprocessosFifo = 0;
fila_t processoAtual;
fila_t *filaAptos = NULL;
fila_t *filaRealisados = NULL;

void fifoImprimeResposta() //Função para criar o arquivo de retorno do programa
{
	fila_t *aux;
	int esperaAcumulado = 0, mediaEspera;
	
	aux = filaRealisados;
	while(aux){ //soma todos os tempos de espera para calcular o tempo médio
		esperaAcumulado = esperaAcumulado + aux->tempoEspera;
		aux = aux->next;	
	}
	mediaEspera = esperaAcumulado / (IDprocessosFifo);
	printf("\n%d\n", mediaEspera);
	aux = filaRealisados;
	while(aux){ // imprime os tempos de cpu na ordem de criação dos processos
		printf("%d\n", aux->tempoCpu);
		aux = aux->next;
	}
}

void filaInsereItemOrdenado(fila_t **fila, fila_t *item)
{ 
  fila_t *aux;
  
  aux = *fila;

  if(*fila == NULL){//se a fila for vazia apenas aponta a fila para o item
    *fila = item;
	(*fila)->next = NULL;
  }
  else {
    while(aux && aux->next && (aux->processoId < item->processoId)) //acha o lugar onde deve ser inserido o item
      aux = aux->next; //em ordem de ID

	if(aux) { // se nao for o ultimo
		item->next = aux->next;
	}else item->next = NULL;
    aux->next = item;
  }

}

void filaInsereItem(fila_t **fila, fila_t *item)
{ //insere item no final da fila
  fila_t *aux;
  
  aux = *fila;

  if(*fila == NULL){//se a fila for vazia apenas aponta a fila para o item
    *fila = item;
	(*fila)->next = NULL;
  }
  else {
    while(aux && aux->next)
      aux = aux->next; //chega no final da fila

    item->next = NULL;
    aux->next = item;
  }
}

fila_t* filaPegaItem(fila_t **fila)
{
  fila_t *aux;
  aux = *fila;
  if(*fila)
    *fila = (*fila)->next;
  return aux;
}

void fifoExecucaoEncerada(int tempo)
{
  fila_t *process;
  if(processoAtual.processoId != -1) {
	processoAtual.tempoCpu = processoAtual.tempoCpu + (tempo - processoAtual.tempoInicio);
  
	process = (fila_t*) malloc(sizeof(fila_t)); //aloca processo para ser colocado na fila de escerados
	process->processoId = processoAtual.processoId;
	process->next = NULL;
	process->tempoCpu = processoAtual.tempoCpu;
	process->tempoEspera = processoAtual.tempoEspera;
	process->tempoInicio = 0;
  
	filaInsereItemOrdenado(&filaRealisados, process);
	//printf("\nProcesso = %d - tempo de execucao = %d - tempo de espera = %d", processoAtual.processoId, processoAtual.tempoCpu, processoAtual.tempoEspera);
  }//ecrever o tempo do processo
  
  processoAtual.processoId = -1;
  fifoExecutaProximo(tempo);
}

void fifoLiberaCpu(int tempo)
{
  fila_t *process;
  
  if(processoAtual.processoId != -1) {
	process = (fila_t*) malloc(sizeof(fila_t));
  
	processoAtual.tempoCpu = processoAtual.tempoCpu + (tempo - processoAtual.tempoInicio);
	processoAtual.tempoInicio = tempo;
  
	process->processoId = processoAtual.processoId;
	process->next = NULL;
	process->tempoCpu = processoAtual.tempoCpu;
	process->tempoEspera = processoAtual.tempoEspera;
	process->tempoInicio = tempo;
  
	processoAtual.processoId = -1;
  
	filaInsereItem(&filaAptos, process);
	
	fifoExecutaProximo(tempo);
  }
}

void fifoExecutaProximo(int tempo)
{
	fila_t *aux;
  if(filaAptos){
    aux = filaPegaItem(&filaAptos);
	
    if(aux != NULL){
      processoAtual.tempoEspera = aux->tempoEspera + (tempo - aux->tempoInicio);
      processoAtual.tempoInicio = tempo;
	  processoAtual.tempoCpu = aux->tempoCpu;
	  processoAtual.processoId = aux->processoId;
	  free(aux);
    }else processoAtual.processoId = -1;
  }else processoAtual.processoId = -1;
}

void fifoAddApto(int tempo)
{
  fila_t *process;
  process = (fila_t*) malloc(sizeof(fila_t));

  process->tempoInicio = tempo;
  process->tempoCpu = 0;
  process->tempoEspera = 0;
  process->processoId = IDprocessosFifo;
  IDprocessosFifo++;

  if(processoAtual.processoId == -1){
    processoAtual.next = NULL;
	processoAtual.processoId = process->processoId;
	processoAtual.tempoInicio = tempo;
	processoAtual.tempoEspera = 0;
	processoAtual.tempoCpu = 0;
	free(process);
  }else{

    filaInsereItem(&filaAptos, process);
  }
}

void fifoLendoArquivo(char *fileName) 
{
    FILE *entrada;
	char buffer[50], *aux;
	int tempo, option;

	processoAtual.processoId = -1;
	
	entrada = fopen(fileName, "r");
	if(entrada == NULL){
		printf("Erro ao abrir o arquivo");
	}else {
	fgets(buffer, 50, entrada);
	while(!feof(entrada)){
		
		aux = strtok(buffer, " ");
		tempo = atoi(aux);
		aux = strtok(NULL, " ");
		option = atoi(aux);
		if(option == 1) {
			fifoAddApto(tempo);
		} else if(option == 2) {
			fifoLiberaCpu(tempo);
		}else if(option == 3){
			fifoExecucaoEncerada(tempo);
		}
			
		fgets(buffer, 50, entrada);		
	}
	fifoImprimeResposta();
	}
	
}
